package webhook

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"github.com/nuttech/bell"
	"github.com/wI2L/jsondiff"
	"gitverse.ru/synapse/kubelatte/pkg/api/common"
	v1alpha12 "gitverse.ru/synapse/kubelatte/pkg/api/v1alpha1"
	"gitverse.ru/synapse/kubelatte/pkg/logs"
	"gitverse.ru/synapse/kubelatte/pkg/storage"
	"go.uber.org/zap"
	"io/ioutil"
	v1 "k8s.io/api/authentication/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"math/big"
	"net"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"testing"
	"text/template"
	"time"

	"github.com/spf13/afero"

	"gitverse.ru/synapse/kubelatte/pkg/validate"

	"github.com/stretchr/testify/assert"
	"gitverse.ru/synapse/kubelatte/pkg/util"
	"gitverse.ru/synapse/kubelatte/pkg/webhook/config"
	"k8s.io/api/admission/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	sidecarConfigFile      = "../../testdata/sidecarconfigs.yaml"
	mutationConfigFile     = "../../testdata/mutationconfigs.yaml"
	admissionReviewFile    = "../../testdata/admissionreview.json"
	admissionReviewBadFile = "../../testdata/admissionreview_bad_without_pod.json"
	emptyHeaderFile        = "../../testdata/empty_header.json"
	wrongHeaderFile        = "../../testdata/wrong_header.json"
	configsPath            = "../../testdata/configs/good_conf_dir_with_correct_configs"
	templateConfigFile     = "../../testdata/sidecarconfigs.yaml"
	triggerConfigFile      = "../../testdata/mutationconfigs.yaml"

	podClusterName      = "TEST_CLUSTER"
	certKey             = "../../testdata/configs/certs/ca.key"
	certCert            = "../../testdata/configs/certs/ca.cert"
	logFileNameInjector = "injector.log"
	dummyPod            = "../../testdata/configs/sanytyPod.yaml"
)

type TestCofig struct {
	httpPort                 int
	tlsPort                  int
	configsPath              string
	templateFile             string
	triggerFile              string
	podClusterName           string
	certKey                  string
	certCert                 string
	certCa                   string
	logFileName              string
	allowDeprecatedTLSConfig bool
	buildInfoLabels          string
	dummyPod                 string
	sidecarConfigTemplate    *template.Template
}

func InitEnv(c *TestCofig, withDefaults bool) {

	os.Setenv(config.ConfigsPath, c.configsPath)
	os.Setenv(config.PodClusterName, c.podClusterName)
	os.Setenv(config.LogFileNameInjector, c.logFileName)
	os.Setenv(config.ServerKey, c.certKey)
	os.Setenv(config.ServerCert, c.certCert)
	os.Setenv(config.SertCa, c.certCa)
	os.Setenv(config.DummyPod, c.dummyPod)
	os.Setenv(config.TLSPort, strconv.Itoa(c.tlsPort))
	os.Setenv("KBLT_MUTATOR", "true")
	os.Setenv("KBLT_VALIDATOR", "true")
	util.KbltMutator = "true"
	util.KbltValidator = "true"
	logs.AtomLevel.SetLevel(zap.DebugLevel)

	if withDefaults {
		if c.configsPath == "" {
			os.Setenv(config.ConfigsPath, configsPath)
			c.configsPath = configsPath
		}
		if c.templateFile == "" && c.configsPath == "" {
			os.Setenv(config.SidecarConfigFile, templateConfigFile)
			c.templateFile = templateConfigFile
		}
		if c.triggerFile == "" && c.configsPath == "" {
			os.Setenv(config.MutationConfigFile, triggerConfigFile)
			c.triggerFile = triggerConfigFile
		}
		if c.podClusterName == "" {
			os.Setenv(config.PodClusterName, podClusterName)
			c.podClusterName = podClusterName
		}
		if c.logFileName == "" {
			os.Setenv(logFileNameInjector, logFileNameInjector)
			c.logFileName = logFileNameInjector
		}
		if c.certKey == "" {
			os.Setenv(config.ServerKey, certKey)
			c.certKey = certKey
		}
		if c.certCert == "" {
			os.Setenv(config.ServerCert, certCert)
			c.certCert = certCert
		}
		if c.dummyPod == "" {
			os.Setenv(config.DummyPod, dummyPod)
			c.dummyPod = dummyPod
		}
	}
}

func setEnv(env ...map[string]string) {
	logs.Logger = zap.NewNop()
	for _, j := range env {
		for k, v := range j {
			os.Setenv(k, v)
		}

	}
}

func TestValidate(t *testing.T) {

}

func TestImmutable(t *testing.T) {
	setEnv(map[string]string{config.EnabledTriggerPrefix: "false", config.ScopeValidation: "false"})
	whsvr := &Server{
		config: &config.WebhookConfig{
			SidecarConfigFile:  sidecarConfigFile,
			MutationConfigFile: mutationConfigFile,
		},
	}

	ar := v1beta1.AdmissionReview{Request: &v1beta1.AdmissionRequest{UID: "jingle bells"}}
	body, err := json.Marshal(ar)
	if err != nil {
		t.Fatalf("Marshalling Admmission Request error: %v", err)
	}

	req, err := http.NewRequest(http.MethodGet, "", bytes.NewBuffer(body))
	if err != nil {
		t.Fatalf("Creatimg request error: %v", err)
	}

	whsvr.immutable(httptest.NewRecorder(), req)
}

func TestHealthz(t *testing.T) {
	whs := NewWebhookServer(nil, nil, &sync.Mutex{})
	req := httptest.NewRequest("POST", "http://localhost:9999/mutate", strings.NewReader("OK"))
	req.Header.Add("Content-Type", "application/json")
	respWriter := httptest.NewRecorder()

	// Act
	whs.healthz(respWriter, req)

	// Assert
	assert.Equal(t, http.StatusOK, respWriter.Code)
}

func TestSetAllStatusesToFailed(t *testing.T) {
	actual := map[string]mutationStatus{"one": succeededMutation, "two": succeededMutation, "three": succeededMutation, "four": succeededMutation}
	setAllStatusesToFailed(actual)
	expected := map[string]mutationStatus{"one": failedMutation, "two": failedMutation, "three": failedMutation, "four": failedMutation}
	assert.Equal(t, expected, actual, "bool string merged")
}

// TempCerts for temporary certificates
type TempCerts struct {
	certsDirectory string
	certFileName   string
	keyFileName    string
}

func GenerateTestCertificates() (*TempCerts, error) {
	var err error
	tempDir, err := ioutil.TempDir("", "test-certs")
	if err != nil {
		return nil, fmt.Errorf("failed to create a temp directory: %s", err)
	}

	certFileName := filepath.Join(tempDir, "cert.pem")
	keyFileName := filepath.Join(tempDir, "key.pem")

	var privateKey *rsa.PrivateKey
	privateKey, err = rsa.GenerateKey(rand.Reader, 2048)

	if err != nil {
		return nil, fmt.Errorf("failed to generate private key: %s", err)
	}

	notBefore := time.Now()
	notAfter := notBefore.Add(365 * 24 * time.Hour)

	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)

	if err != nil {
		return nil, fmt.Errorf("failed to generate serial number: %s", err)
	}

	template := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			Organization: []string{"SBT"},
		},
		NotBefore: notBefore,
		NotAfter:  notAfter,

		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
		IPAddresses:           []net.IP{net.IPv4(127, 0, 0, 1)},
		DNSNames:              []string{"localhost"},
	}

	publicKey := &privateKey.PublicKey
	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey, privateKey)
	if err != nil {
		return nil, fmt.Errorf("Failed to create certificate: %s", err)
	}

	err = writePemBlockToFile(certFileName, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	if err != nil {
		return nil, err
	}

	err = writePemBlockToFile(keyFileName, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)})
	if err != nil {
		return nil, err
	}

	return &TempCerts{
		certsDirectory: tempDir,
		certFileName:   certFileName,
		keyFileName:    keyFileName,
	}, nil
}

func writePemBlockToFile(fileName string, pemBlock *pem.Block) error {
	certOut, err := os.Create(fileName)
	if err != nil {
		return fmt.Errorf("failed to create %s: %s", fileName, err)
	}

	if err := pem.Encode(certOut, pemBlock); err != nil {
		return fmt.Errorf("failed to write block to file: %s", err)
	}

	if err := certOut.Close(); err != nil {
		return fmt.Errorf("unable to close %s: %s", fileName, err)
	}

	return nil
}

type Options func(cofig *TestCofig)

func WithKeyFile(t *testing.T, path string) Options {
	return func(tc *TestCofig) {
		tc.certKey = path
		err := os.Setenv(config.ServerKey, path)
		if err != nil {
			t.Error(err)
		}
	}
}

func WithCertFile(t *testing.T, path string) Options {
	return func(tc *TestCofig) {
		tc.certCert = path
		err := os.Setenv(config.ServerCert, path)
		if err != nil {
			t.Error(err)
		}
	}
}
func WithCaFile(t *testing.T, path string) Options {
	return func(tc *TestCofig) {
		tc.certCa = path
		err := os.Setenv(config.ServerCert, path)
		if err != nil {
			t.Error(err)
		}
	}
}

func WithTLSPort(t *testing.T, port string) Options {
	return func(tc *TestCofig) {
		p, err := strconv.Atoi(port)
		if err != nil {
			t.Error(err)
		} else {
			tc.tlsPort = p
		}
		err = os.Setenv(config.TLSPort, port)
		if err != nil {
			t.Error(err)
		}
	}
}

func newTestWebhookServer(t *testing.T, method, target, bodyPath, headKey, headVal string, defaultInit bool, withCertReloader bool, options ...Options) (*Server, *httptest.ResponseRecorder, *http.Request) {
	logs.Logger = zap.NewNop()
	storage.Storage = &storage.StorageController{}
	storage.Storage.Start(false, false)

	var certReloader *util.CertificatePKIReloader
	fs := afero.NewOsFs()

	data := []byte{}
	testConfig := TestCofig{}

	if defaultInit {
		tmpCerts, err := GenerateTestCertificates()
		if err != nil {
			t.Error(err)
		} else {
			testConfig.certKey = tmpCerts.keyFileName
			testConfig.certCert = tmpCerts.certFileName

		}
	}

	InitEnv(&testConfig, defaultInit)

	for _, opt := range options {
		opt(&testConfig)
	}

	if withCertReloader {
		certReloader = util.NewCertificatePKIReloaderFull(fs, testConfig.certCert, testConfig.certKey, time.Minute*15)
	}

	wc, err := config.NewWebhookConfig()
	if err != nil {
		t.Error(err)
	}

	wc.TLSPort = testConfig.tlsPort
	wc.HTTPPort = testConfig.httpPort
	wc.SidecarConfigFile = testConfig.templateFile
	wc.MutationConfigFile = testConfig.triggerFile
	wc.LogFile = testConfig.logFileName
	wc.KeyFilePath = testConfig.certKey
	wc.CertFilePath = testConfig.certCert
	wc.SanityPodFilePath = testConfig.dummyPod

	wc.AllowDeprecatedTLSConfig = testConfig.allowDeprecatedTLSConfig
	wc.BuildInfoLabels = testConfig.buildInfoLabels
	wc.CaFilePath = testConfig.certCa
	wc.ConfDir = testConfig.configsPath

	whs := NewWebhookServer(wc, certReloader, &sync.Mutex{})
	if bodyPath == "" {
		data = []byte{}
	}

	if bodyPath != "" {
		d, err := ioutil.ReadFile(bodyPath)
		if err != nil {
			t.Error(err)
		}
		data = d
	}

	respWriter := httptest.NewRecorder()

	req := httptest.NewRequest(method, target, strings.NewReader(string(data)))
	req.Header.Add("Content-Type", "application/json")

	return whs, respWriter, req
}

func TestEndpoints(t *testing.T) {
	tests := []struct {
		name     string
		wantFunc func(t *testing.T, i ...interface{})
	}{
		{
			name: "mutate endpoint",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewFile, "Content-Type", "application/json", true, false)
				whs.serve(respWriter, req)
				assert.Equal(t, http.StatusOK, respWriter.Code)
			},
		},

		{
			name: "start webhook server",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, _, _ := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewFile, "Content-Type", "application/json", true, true, WithTLSPort(t, "1"))
				_, _, _, err := whs.Start()
				assert.NoError(t, err)
			},
		},

		{
			name: "start webhook server with bad path to ca file",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, _, _ := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewFile, "Content-Type", "application/json", true, true, WithTLSPort(t, "1"), WithCaFile(t, "/bad_path"))
				_, _, _, err := whs.Start()
				assert.Error(t, err)
			},
		},

		{
			name: "start webhook server with bad request body",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, _, _ := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewBadFile, "Content-Type", "application/json", true, true, WithTLSPort(t, "1"))
				_, _, _, err := whs.Start()
				assert.NoError(t, err)
			},
		},

		{
			name: "start webhook server with set tls port to 1 without cer file",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, _, _ := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewFile, "Content-Type", "application/json", true, false, WithTLSPort(t, "1"), WithKeyFile(t, ""))
				_, _, _, err := whs.Start()
				assert.Error(t, err)
			},
		},

		{
			name: "start webhook server with set tls port to 1 without key file",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, _, _ := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewFile, "Content-Type", "application/json", true, false, WithTLSPort(t, "1"), WithCertFile(t, ""))
				_, _, _, err := whs.Start()
				assert.Error(t, err)
			},
		},

		{

			name: "start webhook server with set tls port to 1 with bad path to cer file",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, _, _ := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewFile, "Content-Type", "application/json", true, false, WithTLSPort(t, "1"), WithCertFile(t, "/bad_path"))
				_, _, _, err := whs.Start()
				assert.Error(t, err)
			},
		},

		{
			name: "start webhook server with set tls port to 1 with bad path to key file",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, _, _ := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewFile, "Content-Type", "application/json", true, false, WithTLSPort(t, "1"), WithKeyFile(t, "/bad_path"))
				_, _, _, err := whs.Start()
				assert.Error(t, err)
			},
		},

		{
			name: "status endpoint",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/status", emptyHeaderFile, "Content-Type", "application/json", true, false)
				whs.updateStatusHndlr(respWriter, req)
				assert.Equal(t, http.StatusOK, respWriter.Code)
			},
		},

		{
			name: "liveness endpoint",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/liveness", emptyHeaderFile, "Content-Type", "application/json", true, false)
				whs.liveness(respWriter, req)
				assert.Equal(t, http.StatusOK, respWriter.Code)
			},
		},

		{
			name: "readyness endpoint",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/readyness", emptyHeaderFile, "Content-Type", "application/json", true, false)
				whs.readyness(respWriter, req)
				assert.Equal(t, http.StatusOK, respWriter.Code)
			},
		},

		{
			name: "readyness endpoint with server not ready state",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/readyness", emptyHeaderFile, "Content-Type", "application/json", true, false)
				whs.Set(ServerNotReady)

				whs.readyness(respWriter, req)
				assert.Equal(t, http.StatusOK, respWriter.Code)
			},
		},

		{
			name: "mutate endpoint with wrong content type",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewFile, "Content-Type", "application/json", true, false)
				whs.Set(ServerReady)

				req.Header.Del("Content-Type")
				req.Header.Add("Content-Type", "text/javascript")

				whs.serve(respWriter, req)
				assert.Equal(t, http.StatusUnsupportedMediaType, respWriter.Code)
			},
		},

		{
			name: "mutate endpoint with server not ready state",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewFile, "Content-Type", "application/json", true, false)
				whs.Set(ServerNotReady)
				whs.serve(respWriter, req)
				assert.Equal(t, http.StatusOK, respWriter.Code)
			},
		},

		{
			name: "mutate endpoint with empty body",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", emptyHeaderFile, "Content-Type", "application/json", false, false)
				whs.Set(ServerReady)
				whs.serve(respWriter, req)
				assert.Equal(t, http.StatusBadRequest, respWriter.Code)
			},
		},
		{
			name: "mutate endpoint with wrong body",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", wrongHeaderFile, "Content-Type", "application/json", true, false)
				whs.Set(ServerReady)
				whs.serve(respWriter, req)
				assert.Equal(t, http.StatusBadRequest, respWriter.Code)
			},
		},

		{
			name: "validate endpoint with server not ready state",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", admissionReviewFile, "Content-Type", "application/json", true, false)
				whs.Set(ServerNotReady)
				whs.validate(respWriter, req)
				assert.Equal(t, http.StatusServiceUnavailable, respWriter.Code)
			},
		},

		{
			name: "validate endpoint with empty body",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/mutate", emptyHeaderFile, "Content-Type", "application/json", false, false)
				whs.Set(ServerReady)
				whs.validate(respWriter, req)
				assert.Equal(t, http.StatusBadRequest, respWriter.Code)
			},
		},

		{
			name: "validate endpoint with wrong content type",
			wantFunc: func(t *testing.T, i ...interface{}) {
				whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/validate", admissionReviewFile, "Content-Type", "application/json", true, false)
				whs.Set(ServerReady)

				req.Header.Del("Content-Type")
				req.Header.Add("Content-Type", "text/javascript")

				whs.validate(respWriter, req)
				assert.Equal(t, http.StatusUnsupportedMediaType, respWriter.Code)
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.wantFunc(t)
		})
	}
}

func TestStartStop(t *testing.T) {
	whsvr := &Server{
		config: &config.WebhookConfig{
			SidecarConfigFile:  sidecarConfigFile,
			MutationConfigFile: mutationConfigFile,
		},
	}
	_, _, _, err := whsvr.Start()
	os.Setenv("KBLT_VALIDATION", "")
	assert.NoError(t, err, "sidecarconfig start server")
	whsvr.Stop()
}

func Test_parseRequest(t *testing.T) {
	type args struct {
		request *v1beta1.AdmissionRequest
		body    []byte
	}
	tests := []struct {
		name    string
		args    args
		want    *common.ARFields
		want1   map[string]interface{}
		wantErr assert.ErrorAssertionFunc
	}{
		{
			name: "test ok",
			args: args{
				request: &v1beta1.AdmissionRequest{
					Kind: metav1.GroupVersionKind{
						Group:   "group",
						Version: "version",
						Kind:    "kind",
					},
					Namespace: "some-namespace",
					Operation: v1beta1.Update,
					UserInfo:  v1.UserInfo{Username: "Katerina"},
					OldObject: runtime.RawExtension{Raw: []byte("{\"oldraw\":\"old rrrr\"}")},
					Object:    runtime.RawExtension{Raw: []byte("{\"raw\":\"rrrr\"}")},
				},
				body: []byte("{\"request\":\"John\", \"age\":30, \"car\":null}"),
			},
			want: &common.ARFields{
				Kind: metav1.GroupVersionKind{
					Group:   "group",
					Version: "version",
					Kind:    "kind",
				},
				Namespace: "some-namespace",
				UserInfo:  common.ARUserInfo{Username: "Katerina"},
				Operation: v1beta1.Update,
				OldObject: map[string]interface{}{"oldraw": "old rrrr"},
				Object:    map[string]interface{}{"raw": "rrrr"},
			},
			want1: map[string]interface{}{"lala": "llad"},
			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
				assert.False(t, err != nil)
				return err != nil
			},
		},
		{
			name: "unmarshal error 1",
			args: args{
				request: &v1beta1.AdmissionRequest{
					Object: runtime.RawExtension{Raw: []byte("{\"raw\":\"rrrr\"}")},
				},
				body: []byte("not-json-string"),
			},
			want:  nil,
			want1: nil,
			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
				assert.True(t, err != nil)
				return err != nil
			},
		},
		{
			name: "unmarshal error 2",
			args: args{
				request: &v1beta1.AdmissionRequest{
					Object: runtime.RawExtension{Raw: []byte("not-json-string")},
				},
				body: []byte("{\"name\":\"John\", \"age\":30, \"car\":null}"),
			},
			want:  nil,
			want1: nil,
			wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
				assert.True(t, err != nil)
				return err != nil
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, got1, err := parseRequest(tt.args.request, tt.args.body)
			if !tt.wantErr(t, err, fmt.Sprintf("parseRequest(%v, %v)", tt.args.request, tt.args.body)) {
				fmt.Println()
				return
			}
			assert.Equalf(t, tt.want, got, "parseRequest(%v, %v)", tt.args.request, tt.args.body)
			assert.Equalf(t, tt.want1, got1, "parseRequest(%v, %v)", tt.args.request, tt.args.body)
			fmt.Println(tt.want, got)
			fmt.Println(tt.want1, got1)
		})
	}
}

func TestWebhookServer_updateStatusHndlr(t *testing.T) {
	type fields struct {
		tlsServer           *http.Server
		httpServer          *http.Server
		config              *config.WebhookConfig
		certificateReloader util.CertificateReloader
		state               serverState
		mux                 *sync.Mutex
	}
	type args struct {
		w http.ResponseWriter
		r *http.Request
	}
	tests := []struct {
		name   string
		fields fields
		args   args
		f      func()
	}{
		{
			name: "ok",
			args: args{
				w: nil,
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			whs, respWriter, req := newTestWebhookServer(t, "POST", "http://localhost:9999/readyness", admissionReviewFile, "Content-Type", "application/json", true, false)
			whs.updateStatusHndlr(respWriter, req)
		})
	}
}

func TestValidateMutation(t *testing.T) {
	var operations []jsondiff.Operation

	t.Run("ScopeValidation_false", func(t *testing.T) {
		_ = os.Setenv(config.ScopeValidation, "false")

		got, _ := ValidateMutation(operations)
		assert.Equalf(t, true, got, "ValidateMutation(%v)", operations)
	})

	t.Run("ScopeValidation_GetScopes=nil", func(t *testing.T) {
		_ = os.Setenv(config.ScopeValidation, "true")
		defer func() { _ = os.Setenv(config.ScopeValidation, "false") }()

		storage.Storage = &storage.StorageController{}
		defer func() { storage.Storage = nil }()
		//storage.Storage.UpdateScope()

		got, _ := ValidateMutation(operations)
		assert.Equalf(t, false, got, "ValidateMutation(%v)", operations)
	})

	t.Run("ScopeValidation_GetScopeItems=nil", func(t *testing.T) {
		_ = os.Setenv(config.ScopeValidation, "true")
		defer func() { _ = os.Setenv(config.ScopeValidation, "false") }()

		storage.Storage = &storage.StorageController{}
		storage.Storage.Start(false, false)
		defer func() { storage.Storage = nil }()
		storage.Storage.UpdateScope(bell.Message{Value: v1alpha12.Scope{
			ObjectMeta: metav1.ObjectMeta{Name: "name", Namespace: "ns"},
			Spec:       v1alpha12.ScopeSpec{Type: validate.Validation}},
		},
		)

		got, _ := ValidateMutation(operations)
		assert.Equalf(t, false, got, "ValidateMutation(%v)", operations)
	})

	t.Run("ScopeValidation_ok", func(t *testing.T) {
		_ = os.Setenv(config.ScopeValidation, "true")
		defer func() { _ = os.Setenv(config.ScopeValidation, "false") }()

		storage.Storage = &storage.StorageController{}
		storage.Storage.Start(false, false)
		defer func() { storage.Storage = nil }()
		storage.Storage.UpdateScope(bell.Message{Value: v1alpha12.Scope{
			ObjectMeta: metav1.ObjectMeta{Name: "name", Namespace: "ns"},
			Spec:       v1alpha12.ScopeSpec{Type: validate.Mutation, Items: []v1alpha12.Item{{}}}},
		},
		)

		got, _ := ValidateMutation(operations)
		assert.Equalf(t, true, got, "ValidateMutation(%v)", operations)
	})
}
